package edu.uwm.cs552;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;


public class HexBoardEditor extends JFrame {

	/**
	 * Keep Eclipse happy
	 */
	private static final long serialVersionUID = 1L;
	private HexBoardPanel hexBoardPanel;
	private HexBoard hexBoard;
	@SuppressWarnings("rawtypes")
	private JComboBox scaleComboBox;
	@SuppressWarnings("rawtypes")
	private JComboBox topographyComboBox;
	private JCheckBox showHiddenCheckBox;
	private JCheckBox meshCheckBox;

	private static final int DEFAULT_WIDTH = 75;
	private static final int DEFAULT_HEIGHT = 50;
	
	private static Integer[] scales = new Integer[] {
		10, 15, 20, 30, 40, 50, 60, 75, 100, 120, 150, 200
	};
	private static Integer defaultScale = 20;
	
	@SuppressWarnings("rawtypes")
	private static final Topography[] topographies = new Topography[]{
		Terrain.TERASE, Terrain.PLAIN, Terrain.MOUNTAIN, Terrain.DESERT,
		Terrain.SMALL, Terrain.MEDIUM, Terrain.LARGE, Terrain.SUBURB, 
		Barrier.BERASE, Barrier.BLOCK, Barrier.INLET, Barrier.RIVER, Barrier.DRAWN
	};
	
	private static final Terrain defaultTerrain = Terrain.PLAIN;

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public HexBoardEditor() {
		super("Hex Board Editor");
		hexBoard = new HexBoard(null,DEFAULT_WIDTH,DEFAULT_HEIGHT);
		getContentPane().setLayout(new BorderLayout());
		hexBoardPanel = new HexBoardPanel();
		MouseAdapter mouseActions = new MouseAdapter(){
			@Override
			public void mouseDragged(MouseEvent arg0) {
				addSelected(arg0.getPoint());
			}
			@Override
			public void mousePressed(MouseEvent arg0) {
				lastCoordinate = null;
				lastEdge = null;
				addSelected(arg0.getPoint());
			}
		};
		hexBoardPanel.addMouseListener(mouseActions);
		hexBoardPanel.addMouseMotionListener(mouseActions);
		getContentPane().add(new JScrollPane(hexBoardPanel));
		JPanel panel = new JPanel();
		panel.add(new JLabel("Magnification:"));
		scaleComboBox = new JComboBox(scales);
		scaleComboBox.setEditable(true);
		panel.add(scaleComboBox);
		scaleComboBox.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				scaleChangeRequested();
			}
		});
		scaleComboBox.setSelectedItem(defaultScale);
		topographyComboBox = new JComboBox(topographies);
		topographyComboBox.setRenderer(new TopographyRenderer());
		topographyComboBox.setMaximumRowCount(13);
		panel.add(topographyComboBox);
		topographyComboBox.setSelectedItem(defaultTerrain);
		showHiddenCheckBox = new JCheckBox("Show Hidden");
		showHiddenCheckBox.setSelected(true);
		panel.add(showHiddenCheckBox);
		showHiddenCheckBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				showHiddenRequest();
			}
		});
		meshCheckBox = new JCheckBox("Show Hex Mesh");
		meshCheckBox.setSelected(false);
		panel.add(meshCheckBox);
		meshCheckBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg) {
				meshChangeRequested();
			}
		});
		getContentPane().add(panel,BorderLayout.NORTH);
		
		JMenuBar bar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		JMenuItem newItem = new JMenuItem("New");
		JMenuItem openItem = new JMenuItem("Open...");
		JMenuItem saveItem = new JMenuItem("Save");
		JMenuItem saveAsItem = new JMenuItem("Save As...");
		JMenuItem quitItem = new JMenuItem("Quit");
		
		newItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doNew();
			}
		});
		openItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doOpen();
			}
		});
		saveItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doSave();
			}
		});
		saveAsItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doSaveAs();
			}
		});
		quitItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				doQuit();
			}
		});
		
		fileMenu.add(newItem);
		fileMenu.add(openItem);
		fileMenu.addSeparator();
		fileMenu.add(saveItem);
		fileMenu.add(saveAsItem);
		fileMenu.addSeparator();
		fileMenu.add(quitItem);
		bar.add(fileMenu);
		setJMenuBar(bar);
		
		this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		this.addWindowListener(new WindowAdapter(){
			@Override
			public void windowClosing(WindowEvent we) {
				doQuit();
			}
		});
		
		hexBoard.addObserver(hexBoardPanel);
		hexBoard.setScale(HexBoard.DEFAULT_SCALE);
		hexBoard.setShowHidden(true);
	}
	
	
	public void scaleChangeRequested() {
		double newScale = defaultScale;
		Object x = scaleComboBox.getSelectedItem();
		if (x instanceof String) {
			try {
				newScale = Float.parseFloat((String)x);
			} catch (NumberFormatException e) {
				scaleComboBox.setSelectedItem(newScale = defaultScale);
			}
		} else if (x instanceof Number) {
			newScale = ((Number)x).doubleValue();
		}
		if (newScale < HexBoard.MIN_SCALE) {
			JOptionPane.showMessageDialog(this, "Scale must be at least " + HexBoard.MIN_SCALE, "Scale error", JOptionPane.ERROR_MESSAGE);
			scaleComboBox.setSelectedItem(newScale = defaultScale);
		}
		hexBoard.setScale(newScale);
	}
	
	private HexCoordinate lastCoordinate;
	private HexEdge lastEdge;
	
	public void addSelected(Point p) {
		if(topographyComboBox.getSelectedItem() instanceof Terrain) {
			HexCoordinate h = HexCoordinate.fromPoint(p, hexBoard.getScale());
			if (h.equals(lastCoordinate)) return;
			h.setTopography((Terrain)topographyComboBox.getSelectedItem());
			hexBoard.putFeature(h);
			lastCoordinate = h;
		}
		if(topographyComboBox.getSelectedItem() instanceof Barrier) {
			HexEdge h = HexEdge.fromPoint(p, hexBoard.getScale());
			if (h.equals(lastEdge)) return;
			h.setTopography((Barrier)topographyComboBox.getSelectedItem());
			hexBoard.putFeature(h);
			lastEdge = h;
		}
	}
	
	public void showHiddenRequest() {
		hexBoard.setShowHidden(showHiddenCheckBox.isSelected());
	}

	public void meshChangeRequested() {
		hexBoard.setDrawMesh(meshCheckBox.isSelected());
	}

	private final HexBoardDialog newDialog = new HexBoardDialog(this);
	private static File file = null;
	
	private void doNew() {
		newDialog.setVisible(true);
		if (newDialog.getResult() != null) {
			hexBoard = newDialog.getResult();
			hexBoard.addObserver(hexBoardPanel);
			file = null;
		}
	}
	
	JFileChooser fileChooser = new JFileChooser();
	
	private void doOpen() {
		switch (fileChooser.showOpenDialog(this)) {
		case JFileChooser.APPROVE_OPTION:
			try {
				File f = fileChooser.getSelectedFile();
				/*
				ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
				HexBoard h = (HexBoard)(ois.readObject());
				ois.close();*/
				BufferedReader br = new BufferedReader(new FileReader(f));
				hexBoard.read(br);
				br.close();
				file = f;
			} catch (Exception e) {
				JOptionPane.showMessageDialog(this, e.getMessage(), "Error opening file", JOptionPane.ERROR_MESSAGE);
			}
		}
	}

	private void doSave() {
		if (file == null) doSaveAs();
		else doSave(file);
	}
	
	private void doSave(File f) {
		try {
			/*
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
			oos.writeObject(hexBoard);
			oos.close();
			*/
			PrintWriter pw = new PrintWriter(new FileWriter(f));
			hexBoard.write(pw);
			pw.close();
			if (pw.checkError()) throw new IOException("File writing failed");
			file = f;
		} catch (IOException e) {
			JOptionPane.showMessageDialog(this, e.getMessage(), "Error saving file", JOptionPane.ERROR_MESSAGE);
		}
	}
	
	private void doSaveAs() {
		switch (fileChooser.showSaveDialog(this)) {
		case JFileChooser.APPROVE_OPTION:
			doSave(fileChooser.getSelectedFile());
		}		
	}
	
	private void doQuit() {
		if (JOptionPane.showConfirmDialog(this, "Really Quit?", "Confirm Exit", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) {
			System.exit(0);
		}
	}
	
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
				int height = screenSize.height * 2 / 3;
				int width = screenSize.width * 2 / 3;
				HexBoardEditor hbe = new HexBoardEditor();
				hbe.setSize(width, height);
				hbe.setLocationRelativeTo(null);
				hbe.setVisible(true);
			}
		});
	}
}
